// TMMDlg.cpp : implementation file
//

#include "stdafx.h"
#include "TMM.h"
#include "Util.h"
#include "TMMDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

CMap<int, int, int, int>  CTMMDlg::m_map;

// CTMMDlg dialog

CTMMDlg::CTMMDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CTMMDlg::IDD, pParent)
	, m_dwPort(9000)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CTMMDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	DDX_Text(pDX, IDC_EDIT1, m_dwPort);
	DDV_MinMaxUInt(pDX, m_dwPort, 256, 65535);
	DDX_Control(pDX, IDC_PACKAGE_LIST, m_lcPackageView);
	DDX_Control(pDX, IDC_IPADDRESS1, m_ipCtrl);
}

BEGIN_MESSAGE_MAP(CTMMDlg, CDialog)
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	//}}AFX_MSG_MAP
	ON_BN_CLICKED(IDOK, &CTMMDlg::OnBnClickedOk)
	ON_BN_CLICKED(IDCANCEL, &CTMMDlg::OnBnClickedCancel)
	ON_WM_TIMER()
END_MESSAGE_MAP()


// CTMMDlg message handlers

BOOL CTMMDlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	// Set the icon for this dialog.  The framework does this automatically
	//  when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon

	m_ipCtrl.SetAddress(0x7F000001); 

	m_lcPackageView.InsertColumn(0, _T("LOCAT"),  LVCFMT_LEFT, 100);
	m_lcPackageView.InsertColumn(1, _T("TYPE"),   LVCFMT_LEFT, 80);
	m_lcPackageView.InsertColumn(2, _T("LENGTH"), LVCFMT_LEFT, 60);
	m_lcPackageView.InsertColumn(3, _T("COMMAND"),LVCFMT_LEFT, 260);

	this->SetTimer(1, 1000, NULL);

	return TRUE;  // return TRUE  unless you set the focus to a control
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CTMMDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// Center icon in client rectangle
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialog::OnPaint();
	}
}

// The system calls this function to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CTMMDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}


void CTMMDlg::OnBnClickedOk()
{
	BYTE addr1,addr2,addr3,addr4;
	m_ipCtrl.GetAddress(addr1, addr2, addr3, addr4);

	CString strAddress;
	strAddress.Format(_T("%d.%d.%d.%d"), 
		addr1, 
		addr2, 
		addr3, 
		addr4 
		); 

	this->UpdateData(TRUE);

	if (m_socket.Create())
	{
		if (m_socket.Connect(strAddress, m_dwPort) )
		{
			m_data.socket = m_socket.Detach();
			m_data.pList  = &m_lcPackageView;

			::AfxBeginThread(SubTreadFunc, &m_data);
		}
		else{
			::AfxMessageBox(_T("Can not connect to server!"));
		}
	}
	else
	{
		::AfxMessageBox(_T("Can not create socket!"));
	}
}

#if 1
UINT CTMMDlg::SubTreadFunc(LPVOID pData)
{
	PSUBTHREADDATA pThreadData = (PSUBTHREADDATA)pData;

	CSocket socket;
	socket.Attach(pThreadData->socket);
	
	BYTE buffer[BUFFER_SIZE];
	while( TRUE ){
		//
		::ZeroMemory(buffer, BUFFER_SIZE);
		//
		int length = socket.Receive(buffer, BUFFER_SIZE);
		if (length == SOCKET_ERROR){
			break;
		}
		else if (length != BUFFER_SIZE){
			continue;
		}
		else{
			PPACKAGE p = (PPACKAGE)buffer;
			if ( p->head != 0x00 || p->tail != 0xFF ){
				continue;
			}

			PPACKAGEDATA pData = (PPACKAGEDATA)p->data;

			pData->dwType = Util::swap_uint32( pData->dwType );
			pData->dwLength = Util::swap_uint32( pData->dwLength );

			int lines = pThreadData->pList->GetItemCount();
			int number = pThreadData->pList->InsertItem(lines, _T("Server->Client"));

			CString strType, strLength;
			if (  pData->dwType < _countof(szTitleMap) &&  pData->dwType > 0){
				strType = szTitleMap[pData->dwType];
			}
			else{
				strType = _T("NONE");
			}

			pThreadData->pList->SetItemText(number, 1, strType);
			
			strLength.Format(_T("%d"), pData->dwLength);
			pThreadData->pList->SetItemText(number, 2, strLength);

			switch (pData->dwType )
			{
			case PT_HANDSHAKE:
				{
					HANDSHAKEACKPACKAGE handshakeAck;
					handshakeAck.dwServerId = 1;
					handshakeAck.dwCpus     = 2;

					PACKAGEDATA data;
					data.dwType   = PT_HANDSHAKE_ACK;
					data.dwLength = sizeof(HANDSHAKEACKPACKAGE); 
		            ::ZeroMemory(data.command, PACKAGE_DATA_COMMAND_LEN);
					Util::arraycopy((char*)&data.command, 0, (char*)&handshakeAck, 0, data.dwLength);

					PACKAGE package;
					::ZeroMemory(&package, sizeof(PACKAGE));

					package.head = 0x00;
					Util::arraycopy((char*)&package.data, 0, (char*)&data, 0, sizeof(PACKAGEDATA));
					package.tail = 0xFF;

					socket.Send(&package, sizeof(PACKAGE));
				}
				break;
			case PT_RUN:
				{
					PRUNTASKPACKAGE runTask = (PRUNTASKPACKAGE)pData->command;
					runTask->dwId = Util::swap_uint32( runTask->dwId );

					m_map.SetAt(runTask->dwId, 0);

					CString strCommand;
					strCommand.Format(_T("%d %s"), runTask->dwId, runTask->task);
					pThreadData->pList->SetItemText(number, 3, strCommand);
				}
				break;
			case PT_KILL:
				{
					PKILLPACKAGE killTask = (PKILLPACKAGE)pData->command;
					killTask->dwId = Util::swap_uint32( killTask->dwId );

					m_map.SetAt(killTask->dwId, 0);

					CString strCommand;
					strCommand.Format(_T("%d"), killTask->dwId);
					pThreadData->pList->SetItemText(number, 3, strCommand);	
				
				}
				break;
			case PT_FINISH_ACK:
				{
					PFINISHPACKAGE finish = (PFINISHPACKAGE)pData->command;
					finish->dwId = Util::swap_uint32( finish->dwId );

					m_map.SetAt(finish->dwId, 0);

					CString strCommand;
					strCommand.Format(_T("%d"), finish->dwId);
					pThreadData->pList->SetItemText(number, 3, strCommand);				
				}
				break;
			default:;
			}
		}
	}

	return 0;
}
#endif

void CTMMDlg::OnBnClickedCancel()
{
	//m_socket.Attach(m_data.socket);

	//m_socket.Close();

	OnCancel();
}

void CTMMDlg::OnTimer(UINT_PTR nIDEvent)
{
	if (m_map.IsEmpty()){
		return;
	}
#if 1
	m_socket.Attach(m_data.socket);

	int key;
	int value;

	POSITION pos = m_map.GetStartPosition();
	while (pos){
		m_map.GetNextAssoc(pos, key, value);
		if (value == 2){
			m_map.RemoveKey(key);
		}
		else if (value == 0){

			FINISHPACKAGE finish;
			finish.dwId = key;

			PACKAGEDATA data;
			data.dwType = PT_FINISH;
			data.dwLength = sizeof(FINISHPACKAGE);
			
			Util::arraycopy((char*)&data.command, 0, (char*)&finish, 0, sizeof(FINISHPACKAGE));
			
			PACKAGE package;
			package.head = 0x00;
			Util::arraycopy((char*)&package.data, 0, (char*)&data, 0, sizeof(PACKAGEDATA));
			package.tail = 0xFF;

			m_socket.Send(&package, sizeof(PACKAGE));

			TRACE(_T("Finish\n"));

			m_map.RemoveKey(key);
		}
	}

#endif

	m_data.socket = m_socket.Detach();

	CDialog::OnTimer(nIDEvent);
}
